/* 
 * File:   AngularAngularUnaryOperator.cpp
 * Author: Gab'z
 * 
 * Created on 6 juin 2012, 02:57
 */

#include "AngularUnaryOperator.h"
#include "../model/memento/StackMemento.h"
#include "../model/Context.h"
#include "../../literal/Constant.h"
#include "../../literal/Expression.h"
#include "../../literal/Complex.h"
#include "model/command/literal/Real.h"

namespace calculator {

    AngularUnaryOperator::AngularUnaryOperator(const std::string name) : Operator(name) {
    }

    AngularUnaryOperator::AngularUnaryOperator(const AngularUnaryOperator& orig) :
    Operator(orig._name) {
    }

    AngularUnaryOperator::~AngularUnaryOperator() {
    }

    std::string AngularUnaryOperator::isExecutable() const {
        if (Context::getInstance()->getCurrentStack()->size() == 0) return "Empty stack";
        if (dynamic_cast<const Complex*> (Context::getInstance()->getCurrentStack()->getConstant(0)) != 0) return "Stack top must be a SimpleNumber";
        return "";
    }

    const Memento* AngularUnaryOperator::createMemento() const throw (CommandException) {
        Stack* stack = new Stack();
        if (Context::getInstance()->getCurrentStack()->empty()) throw CommandException("Not enough Constant in current stack (0/1)");
        stack->push(Context::getInstance()->getCurrentStack()->top());
        return new StackMemento(clone(), stack);
    }

    const Number* AngularUnaryOperator::apply(const Number* number) const throw (ArithmeticException) {
        const SimpleNumber* sn = dynamic_cast<const SimpleNumber*> (number);
        if (sn == 0) throw CommandException("Stack top must be a SimpleNumber");
        double angle = sn->value();
        switch (Context::getInstance()->getParameters()->getAngleUnit()) {
            case Parameters::RADIAN:
                break;
            case Parameters::DEGREE:
                angle *= 180 / PI;
                break;
            default:
                break;
        }
        const Number* resNumber;
        const Real* res = new Real(angle);
        try {
            resNumber = apply(res);
        } catch (ArithmeticException& e) {
            delete res;
            throw;
        }
        delete res;
        return resNumber;
    }

    void AngularUnaryOperator::eval(Stack* stack) const throw (CommandException) {
        if (stack->size() == 0) throw CommandException("Not enough Constant in current stack (0/1)");
        const Constant* c = stack->getConstant(0);
        const Expression* exp = dynamic_cast<const Expression*> (c);
        const Constant* constant;
        if (exp != 0) {
            constant = new Expression(c, this);
        } else {
            const Number* number = dynamic_cast<const Number*> (c);
            if (number == 0) throw CommandException("Stack top must be a Number");

            try {
                constant = apply(number);
            } catch (ArithmeticException& e) {
                throw;
            }
        }
        stack->pop();
        stack->push(constant);
        delete constant;
    }
}
